#pragma comment(lib,"openal32.lib")

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

#include <iostream>
#include "Framework.h"
#include "Timer.h"


#define CASE_RETURN(err) case (err): return "##err"
const char* al_err_str(ALenum err) {
    switch(err) {
        CASE_RETURN(AL_NO_ERROR);
        CASE_RETURN(AL_INVALID_NAME);
        CASE_RETURN(AL_INVALID_ENUM);
        CASE_RETURN(AL_INVALID_VALUE);
        CASE_RETURN(AL_INVALID_OPERATION);
        CASE_RETURN(AL_OUT_OF_MEMORY);
    }
    return "unknown";
}
#undef CASE_RETURN

#define __al_check_error(file,line) \
    do { \
        ALenum err = alGetError(); \
        for(; err!=AL_NO_ERROR; err=alGetError()) { \
            std::cerr << "AL Error " << al_err_str(err) << " at " << file << ":" << line << std::endl; \
        } \
    }while(0)

#define al_check_error() \
    __al_check_error(__FILE__, __LINE__)


#define M_PI 3.14159265
void generateSine_mono16bit(unsigned sample_rate, float freq, ALuint* buf)
{
    size_t buf_size = (1.0f/freq)*2*sample_rate;
	if(buf_size%2)
		buf_size++;

    short* samples = new short[buf_size];
    for(int i=0; i<buf_size; ++i) {
        samples[i] = 32760 * sin( (2.f*float(M_PI)*freq)/sample_rate * i );
		samples[i] /= 3;
    }

	alBufferData(*buf, AL_FORMAT_MONO16, samples, buf_size, sample_rate);
	al_check_error();

    delete[] samples;
}

int main(int argc, char **argv) 
{ 	
	//init openal
    ALFWInitOpenAL();

    //create buffers to store samples
    ALuint buf[3];
    alGenBuffers(3, buf); //generate 3 buffers
    al_check_error();
	
    unsigned sample_rate = 44000; //44kHz

	//first buffer
	generateSine_mono16bit(sample_rate, 440.0f, &buf[0]);
	//second buffer
	generateSine_mono16bit(sample_rate, 587.0f, &buf[1]);
	//third buffer
	generateSine_mono16bit(sample_rate, 660.0f, &buf[2]);
	
    /* Set-up sound source and play buffer */
    ALuint src[3];
    alGenSources(3, src);

    alSourcei(src[0], AL_BUFFER, buf[0]);
	alSourcei(src[0], AL_LOOPING,  AL_TRUE);
    alSourcei(src[1], AL_BUFFER, buf[1]);
	alSourcei(src[1], AL_LOOPING,  AL_TRUE);
    alSourcei(src[2], AL_BUFFER, buf[2]);
	alSourcei(src[2], AL_LOOPING,  AL_TRUE);
		
    al_check_error();
	
	//play sounds
	int state=0;
	Timer t;
	
	std::cout << "Playing first sound" << std::endl;
    alSourcePlay(src[0]);
    al_check_error();
	t.start();
	while(state != 3)
	{
		switch (state)
		{
		case 0:
			if(t.getElapsedTimeInMilliSec() >= 1000.0)
			{
				state = 1;
				std::cout << "Playing second sound" << std::endl;
				alSourcePlay(src[1]);	
			}
			break;

		case 1:
			if(t.getElapsedTimeInMilliSec() >= 2000.0)
			{
				state = 2;
				std::cout << "Playing third sound" << std::endl;
				alSourcePlay(src[2]);		
			}
			break;

		case 2:
			if(t.getElapsedTimeInMilliSec() >= 4000.0) {
				alSourceStop(src[0]);	
				alSourceStop(src[1]);
				alSourceStop(src[2]);
				std::cout << "The End" << std::endl;
				state = 3;
				t.stop();
			}
			break;
		}
	}
	al_check_error();


    /* Dealloc OpenAL */
	ALFWShutdownOpenAL();
    al_check_error();

    return 0;
}